import json

from django.shortcuts import render
from django.views import View
from django.core.serializers import serialize
from django.utils.decorators import method_decorator
from django.views.decorators.cache import cache_page
from django.db.models import Q
from elasticsearch import Elasticsearch

from .models import Menu,Column,Commodity,CommodityOptions,CommodityImage
from utils.resFormatUyil import FormatResponse

# Create your views here.

es = Elasticsearch([{'host': '127.0.0.1', 'port': '9200'}])
# 菜单功能
class MenuView(View):

    def get(self,request,fun):
        '''
        根据用户发送的请求，根据用户的需要进行增删改查的操作，即调用不同的函数方法
        :param request:
        :param fun:
        :return:
        '''
        if not hasattr(self,fun):
            return FormatResponse(status='PARAM_ERROR').res()
        else:
            fun = getattr(self,fun)
            return fun(request)

    # 实现搜索功能的菜单联想
    def search(self,request):
        # 获取传递过来的搜索参数
        search = request.GET.get('search')
        query = {
            "query": {"match": {
                "name": search
            }},
            "highlight": {
                "fields": {"name": {}},
                "pre_tags": "<span style='color:#f40'>",
                "post_tags": "</span>"
            },
            "_source": ["name"]  # 过滤字段
        }
        data = es.search(index='menu', body=query)
        data = [{'_source': hit['_source'], 'highlight': hit['highlight'], '_id': hit['_id']} for hit in
                data['hits']['hits']]

    # 将数据库的菜单数据上传到es当中
    def update(self,request):
        # 获取菜单信息
        menu_query = Menu.objects.filter(status=0)
        # 序列化处理
        menu_list = json.loads(serialize('json',menu_query,ensure_ascii=False))
        # 菜单PUT到ES
        for menu in menu_list:  # 拿到每一个商品放入ES
            es.index(index='menu', id=menu['pk'], body=menu['fields'])

        data = menu_list
        return FormatResponse(data=data).res()

    # 获取菜单信息，因为菜单信息不经常修改，所以这里用上缓存装置
    @method_decorator(cache_page(10*60,cache='hotspot'))
    def get_menu(self,request):
        # 获取状态正常的菜单信息
        menu_query = Menu.objects.filter(status=0)
        # 序列化处理
        menu_list = json.loads(serialize('json',menu_query,ensure_ascii=False))
        '''
        构造数据格式
        {pk:{fields:{主菜单的信息},son:[{子菜单的信息},{}]},pk:{fields:{主菜单的信息},son:[{子菜单的信息},{}]}}
        '''
        data = {}
        for menu in menu_list:
            menu['fields']['id'] = menu['pk']
            fields = menu['fields']
            # 判断该菜单是否是主菜单
            # 当该菜单是子菜单时
            if fields.get('superior'):
                # 判断data当中是否有该菜单的主菜单
                if not data.get(fields['superior']):
                    data[fields['superior']] = {}
                # 判断是否存在son:[]
                if data[fields['superior']].get('son'):
                    data[fields['superior']]['son'].append(fields)
                # 不存在的话就新创建一个
                else:
                    data[fields['superior']]['son'] = [fields]
            # 当前菜单为主菜单
            else:
                # 判断data里面是否有主键信息
                if data.get(menu['id']):
                    data[menu['id']]['fields'] = fields
                else:
                    data[menu['id']] = {}
                    data[menu['id']]['fields'] = fields
        # 主菜单不存在时，子菜单也没有存在的必要了
        data = [i for i in data.values() if i.get('fields')]
        return FormatResponse(data=data).res()


# 栏目功能
class ColumnCommodityView(View):
    # 获取栏目下的商品列表
    def get(self,request):
        # 获取栏目集合
        column_query = Column.objects.filter(status=0).order_by('priority')
        # 序列化处理
        column_list = json.loads(serialize('json',column_query,ensure_ascii=False))
        data = [i['fields'] for i in column_list]
        for i in range(len(column_list)):
            # 获取该栏目下的商品信息
            commodity_query = column_query[i].commodity.filter(status=0).order_by('priority')
            # 序列化处理
            commodity_list = json.loads(serialize('json',column_query,ensure_ascii=False))
            data[i]['commodity'] = []
            for commodity in commodity_list:
                commodity['fields']['id'] = commodity['pk']
                data[i]['commodity'].append(commodity['fields'])

        return FormatResponse(data=data).res()


# 商品功能
class CommodityView(View):
    # 根据用户需求实现不同的功能
    def get(self,request,fun):
        if hasattr(self,fun):
            fun = getattr(fun)
            return fun(request)
        else:
            return FormatResponse(status='PARAM_ERROR').res()

    # 根据用户的搜收关键字来返回商品信息，即商品的搜索功能
    def search(self,request):
        # 获取传入的关键字参数
        search = request.GET.get('search')
        query = {
            "query": {"match": {
                "title": search
            }},
            "highlight": {
                "fields": {"title": {}},
                "pre_tags": "<span style='color:#f40'>",
                "post_tags": "</span>"
            }
        }
        data = es.search(index='ffmall', body=query)  # 搜索包含关键字的商品

        # 拿到关键字商品所在的菜单id，通过菜单id拿菜单下的其他商品
        menu_id_list = [hit["_source"]["menu"] for hit in data['hits']['hits']]

        # 构造查询条件，or
        # 查询关键字商品条件
        should = [{"match": {"title": search}}]
        # 查询关键字商品所在的菜单下商品条件
        for i in menu_id_list:
            term = {
                "term": {
                    "menu": i
                }
            }
            should.append(term)  # should = [{"match": {"title": search}},{第一个menu id}， {第二个menu id}] 完整的查询条件

        query = {
            "query": {
                "bool": {
                    "should": should
                }
            },
            "highlight": {
                "fields": {"title": {}},
                "pre_tags": "<span style='color:#f40'>",
                "post_tags": "</span>"
            },
            "_source": ["title", "subtitle", "cover_picture", "priority"]
        }
        data = es.search(index='ffmall', body=query)
        data = [{'_source': hit['_source'], 'highlight': hit.get('highlight', None), '_id': hit['_id']} for hit in
                data['hits']['hits']]
        return FormatResponse(data=data).res()

    def delete(self, request):
        """
        删除功能
        :param request:
        :return:
        """
        return FormatResponse(data='delete').res()

    # 实现数据库中的商品信息添加到es当中的功能
    def update(self,request):
        # 获取总的商品数据
        commodity_query = Commodity.objects.filter(status=0)
        # 序列化处理
        commodity_list = json.loads(serialize('json',commodity_query,ensure_ascii=False))
        # 将数据添加到es当中去
        for commodity in commodity_list:  # 拿到每一个商品放入ES
            es.index(index='ffmall', id=commodity['pk'], body=commodity['fields'])

        data = commodity_list
        return FormatResponse(data=data).res()

    # 通过点击菜单来获取商品数据
    def by_menu(self,request):
        # 获取菜单对应的id值
        id = request.GET.get('id')
        # 通过id值来获取菜单,该菜单可能是主菜单，也可能是子菜单
        menu_id_query = [menu.id for menu in Menu.objects.filter(Q(id=id) | Q(superior=id),Q(status=0))]
        # 获取菜单下的所有商品
        commodity_query = Commodity.objects.filter(status=0,menu_id__in=menu_id_query)
        # 序列化处理
        commodity_list = json.loads(serialize('json',commodity_query,ensure_ascii=False))
        # 整理数据，传递给前端
        data = []
        for commodity in commodity_list:
            commodity['data'] = {}  # 构造空字典存放数据
            commodity['data']['_source'] = commodity['fields']
            commodity['data']['_id'] = commodity['pk']
            data.append(commodity['data'])
        return FormatResponse(data=data).res()


# 商品详情
class CommodityDetailView(View):

    # 通过用户不同需求来实现不同的功能
    def get(self,request,fun):
        if hasattr(self,fun):
            fun = getattr(self,fun)
            return fun(request)
        else:
            return FormatResponse(status='PARAM_ERROR').res()

    # 获取商品详情的相应选项名和选项
    def get_options(self,request):
        # 获取商品的id
        id = request.GET.get('id')
        # 获取商品选项
        options_query = CommodityOptions.objects.filter(status=0,commodity_id=id)
        # 序列化处理
        options_list = json.loads(serialize('json',options_query,ensure_ascii=False))
        data = {}
        for option in options_list:
            key = option['fields']['option_name']  # 将选项名作为构造data 的key
            fields = option['fields']
            if not data.get(key, None):  # 判断data有没有key这个字段，没有新增
                data[key] = []
            data[key].append({
                'options': fields['options'],
                'price': fields['price'],
                'inventory': fields['inventory'],
                'img': fields['img'],
                'id': option['pk'],
            })

            # 根据选项名的长度进行排序，尺寸在颜色分类前，颜色分类在适用床尺寸前
        data = list(data.items())
        data.sort(key=lambda x: len(x[0]))
        return FormatResponse(data=data).res()

    def by_id(self, request):
        """
        通过商品id获取商品的信息(主标题和副标题)
        :param request:
        :return:
        """
        id = request.GET.get('id')
        commodity_query = Commodity.objects.filter(status=0, id=id)
        commodity_list = json.loads(serialize('json', commodity_query, ensure_ascii=False))
        data = commodity_list[0]['fields']
        return FormatResponse(data=data).res()

    def by_image(self, request):
        """
        获取商品展示图和详情图
        :param request:
        :return:
        """
        get = request.GET
        id = get.get('id')
        belong = get.get('belong')

        img_query = CommodityImage.objects.filter(status=0, belong=belong, commodity_id=id).order_by('priority')
        img_list = json.loads(serialize('json', img_query, ensure_ascii=False))
        data = [i['fields'] for i in img_list]
        return FormatResponse(data=data).res()









